class TextMaker():
    def __init__(self,file_complain=None,file_report=None,file_inquiry=None,this_year=2019,this_period=10,
                 period = 'month', total_name='昆明市总体',remain = 2):
        FormMaker.__init__(self,file_complain,file_report,file_inquiry,this_year,this_period,
                 period,total_name,remain)

        def period_compute(self):
            # 根据当前的年月，推算上月、去年同期，上月去年同期
            last_year = this_year - 1  # 去年int
            if this_period != 1:
                last_period = this_period - 1
                last_period_this_year = this_year
                last_period_last_year = last_year
            else:
                if self.period == 'month':
                    last_period = 12
                if self.period == 'season':
                    last_period = 4
                    last_period_this_year = this_year - 1
                    last_period_last_year = self.last_year - 1

            # 推算去年下期与下下期的年与月
            if self.period == 'month':
                if this_period != 12:
                    next_period = this_period + 1
                    next_period_last_year = last_year
                    if next_period != 12:
                        next_2period = next_period + 1
                        next_2period_last_year = last_year
                    else:
                        next_2period = 1
                        next_2period_last_year = this_year
                else:
                    next_period = 1
                    next_2period = next_period + 1
                    next_period_last_year = this_year
                    next_2period_last_year = this_year

            if self.period == 'season':
                if this_period != 4:
                    next_period = this_period + 1
                    next_period_last_year = last_year
                    if next_period != 4:
                        next_2period = next_period + 1
                        next_2period_last_year = last_year
                    else:
                        next_2period = 1
                        next_2period_last_year = this_year
                else:
                    next_period = 1
                    next_2period = next_period + 1
                    next_period_last_year = this_year
                    next_2period_last_year = this_year

            return [last_year,last_period,last_period_this_year,last_period_last_year,next_period,next_2period,next_period_last_year,next_2period_last_year]

        # 计算并定义各时期（如本期，上期……）的名称
        if this_year!=None and this_period!=None:
            self.last_year, \
            self.last_period,\
            self.last_period_this_year, \
            self.last_period_last_year, \
            self.next_period, \
            self.next_2period, \
            self.next_period_last_year, \
            self.next_2period_last_year = period_compute(self)

            if period == 'month': self.period_name = '月'
            else: self.period_name = '季度'

            self.last_year_name = str(self.last_year)[2:]+'年'
            self.this_year_name =  str(self.this_year)[2:]+'年'
            self.last_period_name = str(self.last_period) + self.period_name
            self.last_period_thisyear_name = str(self.last_period_this_year)[2:] +'年'
            self.last_period_lastyear_name = str(self.last_period_last_year)[2:] +'年'
            self.this_period_name = str(self.this_period) + self.period_name
            self.next_period_name = str(self.next_period) + self.period_name
            self.next_2period_name = str(self.next_2period) + self.period_name
            self.next_period_last_year_name = str(self.next_period_last_year)[2:] +'年'
            self.next_2period_last_year_name = str(self.next_2period_last_year)[2:]+'年'

    ###################    基础函数   ####################
    #如果数值为正，返回上升
    def up_or_dowm(self,num):
        if self.isnan_orinf(num) ==False:
            if num < 0:
                return '下降'
            if num > 0:
                return '上升'
            if num == 0:
                return '持平'
        else:return 'NaN or inf'
    #将储存在字典中的分析内容汇总到一个str中
    def txt_ord_tostr(self,ord_text):
        total_str = ''
        for title,text in ord_text.items():
            total_str += title + '\n'
            total_str += text + '\n'
        return  total_str
    # 将储存在字典中的分析内容汇总到一个文件夹中并保存
    def txt_ord_tostr_save(self,ord_txt,file_name):
        total_str = self.txt_ord_tostr(ord_txt)
        file = open(file_name, "w")
        file.write(total_str)
        file.close()
    # 从dict中提取数据，及包含'总体'二字的index
    def get_frame_and_totalindex(self, ordict, sheet_name='投诉量'):
        #第一默认第一列是lable列
        data = ordict[sheet_name]  # 从字典中获取数据表
        columns_list = list(data.columns)  # 得到数据表的列名列表
        total_index = data[data[columns_list[0]].str.contains('总体') == True].index  # 提取总体行的index
        return data, total_index
    #判断单元格提取出的内容是否为serise，是的话.values[0],提取内容，不是的话pass
    def cell_content(self,cell):
        if isinstance(cell,pd.Series)==True:
            return  cell.values[0]
        else:return  cell
    # 判断数值是否为nan or inf，如果是转为str
    def num_to_str(self,num):
        if isinstance(num,str) != True:
            if cmath.isnan(num) == True:
                num = 'NaN'
            elif cmath.isinf(num) == True:
                num ='inf'
            else:
                num = str(num)
        return num

    ###################    基础文字撰写函数   ####################
    # return str 对单个label去年后两期数据的环比增长率进行预测分析可能的走向
    def forecast_lastyear(self,data,analyse_index,lable_name='昆明市',num_name = '投诉量'):
        columns_list = list(data.columns)
        next_period_lasty_increase = self.cell_content(data[columns_list[-3]][analyse_index])
        next_2period_lasty_increase = self.cell_content(data[columns_list[-2]][analyse_index])
        next_2period_total_increase = self.cell_content(data[columns_list[-1]][analyse_index])
        lastyear_this_period = self.last_year_name+self.this_period_name#去年同期名称


        if next_period_lasty_increase>0 and next_2period_lasty_increase > 0:
            if self.next_period_last_year_name == self.next_2period_last_year_name:
                str_increase = '根据过往情况来看，'+lable_name + self.next_period_last_year_name + self.next_period_name + '、' + \
                               self.next_2period_name + num_name + '连续两月上升，' + self.next_2period_name + num_name + '较'+ \
                               lastyear_this_period + '上升' + self.to_percent(next_2period_total_increase,tostr=True) + ',' \
                               '，因此后两' + self.period_name + num_name + '可能会有所增长。'
            else:
                str_increase = '根据过往情况来看，'+lable_name +self.next_period_last_year_name + self.next_period_name + '、'+ \
                               self.next_2period_last_year_name + self.next_2period_name + num_name + '连续两月上升，'\
                               + self.next_2period_last_year_name + self.next_2period_name + num_name + '较' + \
                               lastyear_this_period + '上升' + self.to_percent(next_2period_total_increase,tostr=True) + '，'\
                               + '，因此后两'+ self.period_name +  num_name + '可能会有所增长。'

        elif next_period_lasty_increase>0:
            str_increase = lable_name +self.next_period_last_year_name + self.next_period_name + num_name + '较'+ \
                           lastyear_this_period + '上升' + self.to_percent(next_period_lasty_increase,tostr=True) + ',' \
                           +'根据' + self.next_period_last_year_name + self.next_period_name + '情况来看，下个' \
                           + self.period_name + num_name + '可能会有所增长。'

        else :str_increase = ''
        return str_increase +  '\n'
    # return str 获取某列数值最高和最低的几个lable的描述性文字
    def get_top_and_last_str(self,dataa,total_index,lable_column,sort_by, num_name ='投诉量',lable_name='区县',
                             total_name = '总体',mode='all',percentage=False,top=3,proportion = False,unit='件',
                             to_pp=False):
        '''
        lable_column：标签列
        lable_name:对标签的统称
        sort_by:用于排序的列
        示例：投诉量 最高的 3 个 区县 为：、、、，投诉量 分别为、 、 、；投诉量 最低的3 个 区县 为……。
        proportion top数据占总体比例的描述
        mode：all 、top 、last
        '''
        data = dataa.copy()
        data_no_total= data.drop(total_index)  # 去掉总数，进行区域分析
        #############   进行top数据描述   ############
        data_no_total.sort_values(by=[sort_by], ascending=False, inplace=True)  # 对数据进行排序，true升序，false降序
        data_no_total.reset_index(drop=True,inplace=True)#重设index并删除原有index
        top_lable = list(data_no_total[lable_column][:top].values) #获得top的lable名称
        top_num = list(data_no_total[sort_by][:top].values) #获得top的lable数值
        top_lable = [self.num_to_str(i) for i in top_lable ]#为避免数据类型错误，均转换成str
        if percentage == True: #如果要转化成百分比则进行转化
            top_num_s = self.list_to_percentage(top_num,tostr=True)
        elif to_pp == True:# 如果要转换为百分点
            top_num_s = [self.round(i*100,tostr=True) + '个百分点' for i in top_num]
        else:
            top_num_s = [self.round(i,tostr=True) + unit for i in top_num]
        top_lable_str = '、'.join(top_lable)#为将列表元素以顿号分隔开，转换成一整个str
        top_num_str = '、'.join(top_num_s)
        str_top = num_name + '排名前'+ self.num_to_str(top) +  '的' + lable_name + '为：' + top_lable_str + '，'+ \
                      num_name + '分别为'+ top_num_str + '；'

        ##############    进行top占比描述    ################
        if proportion == True:
            total_num = self.cell_content(data[sort_by][total_index])
            top_num_sum = sum(top_num)
            top_proportion = self.to_percent(top_num_sum/total_num,tostr=True)
            top_proportion_each = self.list_to_percentage(list(np.array(top_num)/total_num),tostr=True)
            top_proportion_each =  '、'.join(top_proportion_each)
            str_top_proportion = '分别占' + total_name + num_name + '的'+ top_proportion_each + '，合计占总' + num_name + '的' + \
                                 top_proportion +'；'
            str_top += str_top_proportion

        #############   进行last数据描述   ############
        data_no_total.sort_values(by=[sort_by], ascending=True, inplace=True)  # true升序，false降序
        data_no_total.reset_index(drop=True, inplace=True)  # 重设index并删除原有index
        last_lable = list(data_no_total[lable_column][:top].values)
        last_lable = [self.num_to_str(i) for i in last_lable]
        last_num = list(data_no_total[sort_by][:top].values)
        if percentage == True:
            last_num = self.list_to_percentage(last_num,tostr=True)
        elif to_pp == True:# 如果要转换为百分点
            last_num = [self.round(i*100,tostr=True) + '个百分点' for i in last_num]
        else:
            last_num = [self.round(i,tostr=True) + unit for i in last_num]
        last_lable_str =  '、'.join(last_lable)
        last_num_str =  '、'.join(last_num)
        str_last = num_name + '最低的' + self.num_to_str(top) + '个' + lable_name + '为：' + last_lable_str + '，' + \
                      num_name + '分别为' + last_num_str + '。'

        if mode == 'all': return str_top + str_last + '\n'
        if mode == 'top': return str_top + '\n'
        if mode == 'last': return str_last + '\n'
    # return str 对单个label的发展情况进行分析，unit1 对应数量,unit2 对应数量增长
    def one_lable_str(self,data,analyse_index,lable_name='昆明市',num_name ='投诉量',unit1 ='件',unit2 ='件',proporat=False,
                      total_name='总体',mode='all',percent=False):
        '''
        mood: 'all'加入同比环比增长率分析；num，只说总量和同比环比的增长率
        proporat：为True加入占总体比重变化的分析
        '''
        # 指标整理
        quantity = self.cell_content(data[self.this_period_column_name][analyse_index])
        if percent ==True:quantity = self.to_percent(quantity,tostr=True)
        proportion_this_period = self.cell_content(data['本期占比'][analyse_index])
        proportion_last_period = self.cell_content(data['上期占比'][analyse_index])
        proportion_last_year = self.cell_content(data['去年同期占比'][analyse_index])
        proportion_tolast_period_increase = (proportion_this_period - proportion_last_period)*100
        proportion_tolast_year_increase = (proportion_this_period - proportion_last_year) * 100

        to_last_period_increase = self.cell_content(data['环比增长量'][analyse_index])
        to_last_year_increase = self.cell_content(data['同比增长量'][analyse_index])
        to_last_period_increase_proportion = self.cell_content(data['环比增长量占比'][analyse_index])
        to_last_year_increase_proportion = self.cell_content(data['同比增长量占比'][analyse_index])

        to_last_period_ratio = self.cell_content(data['环比增长率'][analyse_index])
        to_last_year_ratio = self.cell_content(data['同比增长率'][analyse_index])
        lastperiod_to_lastyear_ratio = self.cell_content(data['上期同比增长率'][analyse_index])
        to_lastyear_ratio_increasew = self.cell_content(data['同比增长率增幅'][analyse_index])

        # 数量及环比增长情况分析
        total_str = self.this_period_name + lable_name + num_name +'为' + self.num_to_str(quantity) + unit1 + '，'
        tolast_period_str1 = '较'+ self.last_period_name + self.up_or_dowm(to_last_period_increase) + self.num_to_str(abs(to_last_period_increase)) + unit2 + '，'
        tolast_period_str2 = '环比增长率为' + self.to_percent(to_last_period_ratio,tostr=True) + '；'
        tolast_period_str = tolast_period_str1 + tolast_period_str2
        proport_tolast_period_str = '从环比增长量占比情况来看，'+ self.this_period_name + lable_name + num_name + '环比增长量占' \
                                    + total_name + '比重为' +  self.to_percent(to_last_period_increase_proportion,tostr=True)+ '；'

        # 数量及同比增长情况分析
        tolast_year_str1 = num_name + '较去年同期' + self.up_or_dowm(to_last_year_increase) + self.num_to_str(abs(to_last_year_increase)) + unit2 +'，'
        tolast_year_str2 = '同比增长率从' + self.last_period_name + '的' + self.to_percent(lastperiod_to_lastyear_ratio,tostr=True) + \
                     self.up_or_dowm(to_lastyear_ratio_increasew) + self.num_to_str(abs(to_lastyear_ratio_increasew)) + '个百分点，至' + \
                           self.to_percent(to_last_year_ratio,tostr=True) + '；'
        tolast_year_str = tolast_year_str1 + tolast_year_str2
        proport_tolast_year_str = '从同比增长量占比情况来看，'+ self.this_period_name + lable_name + num_name + '同比增长量占' \
                                    + total_name + '比重为' +  self.to_percent(to_last_year_increase_proportion,tostr=True)+ '；'

        proport_total_str = '从占比情况来看，'+ lable_name + self.this_period_name + num_name + '占' + total_name + num_name\
                           + '的比例为' + self.to_percent(proportion_this_period,tostr=True) + '；' + '占比较上期'+ \
                           self.up_or_dowm(proportion_tolast_period_increase) + self.round(abs(proportion_tolast_period_increase),tostr=True) + '个百分点'\
                        + '较去年同期' + self.up_or_dowm(proportion_tolast_year_increase) + self.round(abs(proportion_tolast_year_increase),tostr=True)+ '个百分点。'

        if mode == 'all':
            if proporat == True:
                lable_str = total_str + tolast_period_str + proport_tolast_period_str[:-1]  +'。\n'+ tolast_year_str + proport_tolast_year_str[:-1]  + '。\n'+ proport_total_str
            else:
                lable_str = total_str + tolast_period_str[:-1] +'。\n' + tolast_year_str

        if mode == 'num':
            lable_str = total_str + tolast_period_str1 + tolast_year_str1

        return lable_str[:-1] +'。\n'
    # 同上，用于只有两期数据
    def one_lable_str_2period(self, data, analyse_index,p1_name,p2_name, lable_name='五华区', num_name='投诉量',
                              unit='件', total_name='昆明市总体',total_name2=None,
                              p_increase = True, p_quantity= True, mode='all', percentage=False):
        '''
        :param  mood: 数据为多重索引时生效，决定比例分析是使用 占总体 还是 占类别，还是都用 'all''total''type'三种
        :param  p_quantity：为True进行数量占比分析
        :param  p_increase：为True进行增长量占比分析
        :param  percentage：为True将本期，上期数值转化为百分比，增长量*100，unit2设定为'个百分点'
        :param  total_name2 如果多重索引为必填项，为indexdLevel[0]的总体名称
        '''

        unit2 = unit
        if total_name2 == None: total_name2 = total_name
        ########################   指标整理  ########################
        quantity_last = self.cell_content(data.loc[analyse_index,p1_name])  # 取出上期数值
        quantity = self.cell_content(data.loc[analyse_index,p2_name])#取出本期数值

        proportion_this_period = self.cell_content(data.loc[analyse_index,'本期占比']) # 取出本期占比
        proportion_last_period = self.cell_content(data.loc[analyse_index,'上期占比']) # 取出上期占比
        proportion_tolast_period_increase = self.cell_content(data.loc[analyse_index,'占比增长'])*100  # 取出占比增长(pp)

        for column in list(data.columns):
            if column[-3:] == '增长量':
                increase_quantity_column = column
            elif column[-3:] == '增长率':
                increase_ratio_column = column
        to_last_period_increase = self.cell_content(data.loc[analyse_index,increase_quantity_column])#增长量
        to_last_period_ratio = self.cell_content(data.loc[analyse_index,increase_ratio_column])#增长率
        to_last_period_increase_proportion = self.cell_content(data.loc[analyse_index,'增长量占比'])

        if '本期占类别比' in data.columns:# 如果数据中存在占类别比
            type_proportion_this_period = self.cell_content(data.loc[analyse_index,'本期占类别比'])  # 取出本期占比
            type_proportion_last_period = self.cell_content(data.loc[analyse_index,'上期占类别比'])  # 取出上期占比
            type_proportion_tolast_period_increase = self.cell_content(data.loc[analyse_index,'占类别比增长']) * 100  # 取出占比增长(pp)
            type_to_last_period_increase_proportion = self.cell_content(data.loc[analyse_index,'类别增长量占比'])

        # 如果要进行百分比分析则进行如下转换
        if percentage == True:
            quantity_last = self.to_percent(quantity_last, tostr=True)  # 如果要转化为百分比则将数值转化为百分比
            quantity = self.to_percent(quantity, tostr=True)  # 如果要转化为百分比则将数值转化为百分比
            to_last_period_increase = to_last_period_increase*100
            unit2 = '个百分点'
        ########################   文字模板  ########################
        ##### 数量及增长情况分析#####
        # 本期数值
        total_str = p2_name + lable_name + num_name + '为' + self.round(quantity,tostr=True) + unit + '，'
        # 较上期增长情况
        tolast_period_str1 = '较' + p1_name + '(' + self.round(quantity_last,tostr=True) + unit + ')'+\
                             self.up_or_dowm(to_last_period_increase) + \
                             self.round(abs(to_last_period_increase),tostr=True) + unit2 + '，'
        # 增长率
        tolast_period_str2 = increase_ratio_column + '为' + self.to_percent(to_last_period_ratio, tostr=True) + '；'

        ##### 占总体比例情况分析 #####
        # 数量占比情况
        proport_quantity_start = '从'+ num_name +'占比情况来看，' + lable_name + p2_name + num_name
        proport_quantity_total = '占' + total_name2 + num_name + '的比例为' + \
                                 self.to_percent(proportion_this_period, tostr=True) + '；' + '占比较' + \
                                 p1_name + '(' + self.to_percent(proportion_last_period, tostr=True) + ')' + \
                                 self.up_or_dowm(proportion_tolast_period_increase) + \
                                 self.round(abs(proportion_tolast_period_increase), tostr=True) + '个百分点' + '；'
        #增长量占比情况
        proport_increace_start = '从'+ increase_quantity_column +'占比情况来看，' + p2_name + lable_name + num_name + \
                                    increase_quantity_column
        proport_increace_total = '占' + total_name2 + num_name + '的比重为' + \
                                    self.to_percent(to_last_period_increase_proportion,tostr=True) + '；'

        ##### 占类型比例情况分析 #####
        if '本期占类别比' in data.columns:# 如果数据中存在占类别比
            # 增长量占比情况
            proport_quantity_type = '占' +  total_name + num_name  + '的比例为' + \
                                     self.to_percent(type_proportion_this_period, tostr=True) + '；' + '占比较' + \
                                     p1_name + '(' + self.to_percent(type_proportion_last_period, tostr=True) + ')'+\
                                     self.up_or_dowm(type_proportion_tolast_period_increase) + \
                                     self.round(abs(type_proportion_tolast_period_increase), tostr=True) + '个百分点' + '；'
            proport_increace_type = '占'+  total_name + num_name  + '的比重为' + \
                                    self.to_percent(type_to_last_period_increase_proportion, tostr=True) + '；'

        ########################   根据参数合成文字  ########################
        #确定 总体分析 增长量占比分析 数量占比分析的内同
        if percentage == True:#只留总体分析
            total_analyse_str = total_str + tolast_period_str1
            lable_str = total_analyse_str[:-1] + '。\n'
        else:
            total_analyse_str = total_str + tolast_period_str1 + tolast_period_str2
            if '本期占类别比' in data.columns:
                if mode == 'all':
                    proport_increace = proport_increace_start + proport_increace_total + proport_increace_type
                    proport_quantity = proport_quantity_start + proport_quantity_total + proport_quantity_type
                if mode == 'type':
                    proport_increace = proport_increace_start + proport_increace_type
                    proport_quantity = proport_quantity_start + proport_quantity_type
                if mode == 'total':
                    proport_increace = proport_increace_start + proport_increace_total
                    proport_quantity = proport_quantity_start + proport_quantity_total
            else:
                proport_increace = proport_increace_start + proport_increace_total
                proport_quantity = proport_quantity_start + proport_quantity_total

            #根据参数确定最终输出文字
            if (p_quantity == True) and (p_increase == True):
                lable_str = total_analyse_str[:-1] + '。\n'  + proport_quantity[:-1] + '。\n'  + proport_increace[:-1] + '。\n'
            elif p_quantity == True:
                lable_str = total_analyse_str[:-1] + '。\n'  + proport_quantity[:-1] + '。\n'
            elif p_increase == True:
                lable_str = total_analyse_str[:-1] + '。\n'  + proport_increace[:-1] + '。\n'
            else:
                lable_str = total_analyse_str[:-1] + '。\n'

        return lable_str
    # return ordict 对整个表单进行分析：本期数量、同比环比增量top排名 + top lable 分别分析
    def one_sheet_str(self,data, total_index, save_name,data_name = '投诉',lable_column = '量', lable_name='主体',
                      total_name = '总体',top = 'all', unit ='件'):
        '''
        :param data: dataframe
        :param total_index: 总量所在的行index
        :param save_name: 保存的文件名'.txt'
        :param lable_column: 标签所在的列的名称
        :param lable_name: 标签的统称如'区县','主体'
        :param total_name: 总量的名称，如：总体、商品类、服务类
        :param top: ‘0’，‘all’，‘int’：为‘0’代表不做排名分析，直接对所有lable单独分析，all对所有lable进行分析，同时也做排名分析
        :param unit1: 单位：如‘件’，‘元’
        :return: ordict  拉动因素分析、lable1分析、lable2分析…… 并保存到self.output文件夹
        '''

        lables_str_ord = collections.OrderedDict()

        drive = 1
        if top != 0 and top != 'all':#如果top非0非all，则不便
            rank_top = top #排名分析的top数量
        elif top == 'all':#若top ==all top值为行数
            top = data.shape[0]-1 #需去掉总体行
            rank_top = 5#排名分析的top数量
        else:  # 如果top=0，top值为行数，不做拉动因素分析
            top = data.shape[0]-1  #需去掉总体行
            drive = False # 不做拉动因素分析

        ###########  拉动因素分析  ###########
        data_top = data.copy()  # 将数据复制一份避免做排名分析时打乱顺序
        if drive != False:
            #对数量、环比增长量、同比增长量进行排名分析
            top_quntity = self.get_top_and_last_str(data_top, total_index,lable_column, self.this_period_column_name,
                                                    num_name=data_name+'量', lable_name=lable_name, total_name = total_name,mode='top',
                                                    percentage=False, top=rank_top, proportion=True, unit=unit)
            top_increase_period = self.get_top_and_last_str(data_top, total_index,lable_column, '环比增长量',
                                                            num_name=data_name+'环比增长量', lable_name=lable_name,total_name = total_name,
                                                            mode='top',percentage=False, top=rank_top, proportion=True, unit=unit)
            top_increase_year = self.get_top_and_last_str(data_top, total_index, lable_column, '同比增长量',
                                                          num_name=data_name+'同比增长量', lable_name=lable_name,total_name = total_name,
                                                          mode='top',percentage=False, top=rank_top, proportion=True, unit=unit)
            top_analyse = top_quntity + top_increase_period + top_increase_year
            lables_str_ord['拉动因素分析' + '\n'] = top_analyse + '\n'
        ###########  增长率排名分析  ###########
        top_increase_period_rate = self.get_top_and_last_str(data_top, total_index, lable_column, '环比增长率',
                                                        num_name=data_name+'环比增长率', lable_name=lable_name,total_name=total_name,
                                                        mode='all', percentage=True, top=rank_top, proportion=False,unit=unit)
        top_increase_year_rate = self.get_top_and_last_str(data_top, total_index, lable_column, '同比增长率',
                                                      num_name=data_name+'同比增长率', lable_name=lable_name, total_name=total_name,
                                                      mode='all', percentage=True, top=rank_top, proportion=False,unit=unit)
        top_rate_analyse = top_increase_period_rate + top_increase_year_rate
        lables_str_ord['增长情况排名分析' + '\n'] = top_rate_analyse + '\n'
        ###########  lable单独分析  ###########
        data_part = data.drop(total_index)  # 去除总体列
        data_part.sort_values(by=self.this_period_column_name, ascending=False, inplace=True)  # 降序排序
        data_part.reset_index(drop=True, inplace=True)  # 重设index
        for index in range(top):
            lable = self.num_to_str(data_part[lable_column][index])  # 获取标签名称
            # 进行单一lable的分析
            lable_str = self.one_lable_str(data_part, index, lable_name=lable, num_name=data_name+'量',total_name = total_name,
                                           unit1=unit, unit2=unit,proporat=True, mode='all')
            # 进行趋势分析
            lable_future_str = self.forecast_lastyear(data_part, index, lable_name=lable, num_name=data_name+'量')
            # 将分析的结果存入该sheet分析的字典
            lables_str_ord[lable + data_name+'情况分析' + '\n'] = lable_str + lable_future_str + '\n'

        self.txt_ord_tostr_save(lables_str_ord, self.floder_form + save_name)
        return lables_str_ord
    # 同上，用于只有两期数据
    def one_sheet_str_2period(self,data, p1_name,p2_name,save = True,save_name=None,data_name = '投诉',lable_name='区县',
                              total_name = '昆明市总体',top = 'all', unit ='件',rank_mode = 'all',num_name_end = '量',
                              p_rank=True, p_increase=True, p_quantity=True,lable_mode = 'all',percentage=False,
                              rank_only = False,total_name2 = None):
        '''
        :param data: dataframe,总体lable必须包含总体二字，不然无法识别
        :param p1_name,p2_name: str 两个时间段的名称
        :param save_name: str 保存的文件名'.txt'
        :param data_name: str '投诉' '举报' '咨询'
        :param lable_name: 标签的统称如'区县','主体'
        :param total_name: 总量的名称，如：昆明市总体、商品类总体、服务类总体
        :param  total_name2 如果多重索引为必填项，为indexdLevel[0]的总体名称
        :param top: ‘0’，‘all’，‘int’：为‘0’代表不做排名分析，直接对所有lable单独分析，all对所有lable进行分析，同时也做排名分析
        :param unit: 单位：如‘件’，‘元’，进行百分比分析和百分点分析时会自动转换
        :param rank_mode str 用于排名分析'all' 'top' 'last'
        :param num_name_end str 数据名称的结尾，如 '量'，'平均办结时长','满意度'
        :param p_rank bool 在排名分析中是否加入占比的分析
        :param p_increase bool 用于lable单独分析时，是否进行增长量占比分析
        :param p_quantit bool 用于lable单独分析时，是否进行数量转笔分析
        :param lable_mode lable单独分析时one_lable_str_2period的mode参数，只在多重索引时有效,决定比例分析是使用 占总体 还是 占类别，还是都用 'all''total''type'三种
        :param percentage bool  排名分析-数量 及 lable单独分析时-本期、上期 转换成百分比
        :param rank_only boll 为True只做总体与拉动因素分析
        :return: ordict  拉动因素分析、lable1分析、lable2分析…… 并保存到self.output文件夹
        '''
        ############    信息提取函数    ############
        #获取要分析的lable列列名（list or str）增长量（str）、增长率列名（str），1级索引lable（list，如果为单层索引返回None），
        def get_info(data):
            # 获取reset index后要分析的列名
            lable_column = data.index.names

            # 获取增长量与增长率的列名
            for column in list(data.columns):
                if column[-3:] == '增长量':
                    increase_quantity_name = column
                if column[-3:] == '增长率':
                    increase_ratio_name = column

            # 获取总体index
            total_index_list = []
            for or_index in data.index:
                if type(or_index)==str:
                    if '总体' in or_index:
                        total_index_list.append(or_index)
            if len( total_index_list)==1:
                or_total_index = total_index_list[0]
            elif len( total_index_list)==0:
                or_total_index = None
            else:print('分析内容中有多个index中包含 总体 二字')

            return lable_column,or_total_index,increase_quantity_name,increase_ratio_name
        #获取用于行分析的top值，用于排名分析的rank_top,判定是否做拉动因素分析的pulling_factors
        def get_top_pulling(data,top):
            pulling_factors = 1
            if isinstance(data.index, pd.MultiIndex) == True:#如果数据为多层索引，不做排名分析
                if top != 0:
                    top = 0
                    print('统计表 {} 为多层索引，无法进行拉动因素等排名分析，直接进行各行的分析'.format(lable_column))
            lable_num = data.shape[0]-1
            if top != 0 and top != 'all':#如果top非0非all，则不变
                if top <=lable_num:
                    rank_top = top #排名分析的top数量
                else:rank_top = lable_num
            elif top == 'all':#若top ==all top值为行数
                top = lable_num  #需去掉总体行
                if top >= 5:
                    rank_top = 5  # 排名分析的top数量
                else: rank_top = top
            else:  # 如果top=0，top值为行数，不做拉动因素分析
                top = lable_num   #需去掉总体行
                pulling_factors = False # 不做拉动因素分析
            return top,rank_top,pulling_factors
        #单层索引输出reset_index之后的reset_index
        def get_total_index(data):
            data_reset = data.reset_index()
            total_index_list = list(data_reset[data_reset[data.index.names[0]].str.contains('总体') == True].index)
            if len(total_index_list)==1:
                reset_total_index = total_index_list[0]
            elif len(total_index_list)==0:
                print('one_sheet_str_2period：传入数据总体行必须包含 总体 二字')
            else:
                print('one_sheet_str_2period：传入数据有多行包含 总体 二字无法确定总体行')
            return reset_total_index,data_reset
        to_pp = percentage

        ##############    分析函数    #############
        # 单层索引：拉动因素分析，对数量、增长量、增长率进行排名分析
        def pulling_factors_analyse(lables_str_ord,data_reset, reset_total_index,lable_column,rank_top,
                                    increase_quantity_name, increase_ratio_name,p_rank):
            if percentage == True : p_rank = False
            lable_column = lable_column[0]
            top_quntity = self.get_top_and_last_str(data_reset, reset_total_index,lable_column, p2_name,
                                                    num_name=data_name + num_name_end, lable_name=lable_name,
                                                    total_name = total_name,mode=rank_mode,percentage=percentage,
                                                    top=rank_top, proportion=p_rank, unit=unit,to_pp=False)
            name_increase_quntity = data_name + num_name_end + increase_quantity_name
            top_increase_quntity = self.get_top_and_last_str(data_reset, reset_total_index,lable_column,increase_quantity_name,
                                                            num_name=name_increase_quntity, lable_name=lable_name,
                                                            total_name = total_name,mode=rank_mode,percentage=False,
                                                            top=rank_top, proportion=p_rank, unit=unit,to_pp=to_pp)
            name_increase_period = data_name + num_name_end + increase_ratio_name
            top_increase_period = self.get_top_and_last_str(data_reset, reset_total_index, lable_column,increase_ratio_name,
                                                            num_name=name_increase_period,lable_name=lable_name,
                                                            total_name=total_name, mode='all', percentage=True,
                                                            top=rank_top,proportion=False, unit=unit,to_pp=False)
            top_analyse = top_quntity + top_increase_quntity + top_increase_period
            lables_str_ord['拉动因素分析' + '\n'] = top_analyse + '\n'
            return lables_str_ord
        #单层索引：lable单独分析
        def lable_analyse_one_layer(lables_str_ord,data,or_total_index,top,lable_level1=None):
            if or_total_index == None:
                pass
            else:
                data_part = data.drop(or_total_index)  # 去除总体行
                data_part.sort_values(by=p2_name, ascending=False, inplace=True)  # 降序排序
                top_list = list(data_part.index)[:top]

                for index in top_list:
                    lable = self.num_to_str(index)  # 获取标签名称
                    # 进行单一lable的分析
                    lable_str = self.one_lable_str_2period(data_part,index,p1_name,p2_name,lable_name=lable,
                                                           num_name=data_name + num_name_end,total_name = or_total_index,total_name2 = total_name2,unit=unit,
                                                           p_increase=p_increase, p_quantity= p_quantity, mode=lable_mode,percentage=percentage)
                    # 将分析的结果存入该sheet分析的字典
                    lables_str_ord[lable + data_name+'情况分析' + '\n'] = lable_str + '\n'
            return lables_str_ord

        #单层索引：信息提取 + 拉动 + lable单独整合
        def one_layer_analyse(data,top,to_str = False,lable_level1=None):
            lables_str_ord = collections.OrderedDict()
            if isinstance(data.index, pd.MultiIndex) == False:
                # 提取total_index,reset_data,rank_top等参数做排名分析
                lable_column, or_total_index, increase_quantity_name, increase_ratio_name = get_info(data)
                top, rank_top, pulling_factors = get_top_pulling(data, top)
                reset_total_index, data_reset = get_total_index(data)
                if or_total_index == None:
                    pass
                else:
                    #####  总体行分析  #####
                    if or_total_index != total_name:
                        lables_str_ord[or_total_index] = self.one_lable_str_2period(data, or_total_index, p1_name, p2_name,
                                                            lable_name=or_total_index,num_name=data_name + num_name_end,
                                                            total_name=total_name,unit=unit,p_increase=p_increase,
                                                            p_quantity= p_quantity, mode='total',percentage=percentage)
                    if or_total_index == total_name:
                        lables_str_ord[or_total_index] = self.one_lable_str_2period(data, or_total_index, p1_name, p2_name,
                                                            lable_name=or_total_index,num_name=data_name + num_name_end,
                                                            total_name=or_total_index,unit=unit,p_increase=False,
                                                            p_quantity= False, mode=lable_mode,percentage=percentage)

                     #####  拉动因素分析  #####
                    if pulling_factors != False:
                        lables_str_ord = pulling_factors_analyse(lables_str_ord, data_reset, reset_total_index,
                                                                 lable_column, rank_top,increase_quantity_name,
                                                                 increase_ratio_name,p_rank)

                    ######   lable单独分析  #####
                    if rank_only == False:
                        lables_str_ord = lable_analyse_one_layer(lables_str_ord, data, or_total_index,top,lable_level1=lable_level1)

                    ######   保存与输出   #####
                    if to_str == True:
                        analyse_str = self.txt_ord_tostr(lables_str_ord)
                        return analyse_str
                    else:
                        return lables_str_ord
            else:
                print('最多只支持两级索引')

        # 多层索引分析:相当于吧单层索引分析循环了几遍
        def lable_analyse_MultiIndex(data,top):
            lables_str_ord = collections.OrderedDict()
            level1_lable_list = data.index.levels[0]
            for level1_lable in level1_lable_list:
                if level1_lable[-2:] == '总体':
                    lables_str_ord[level1_lable] = self.one_lable_str_2period(data, level1_lable, p1_name, p2_name,
                                                  lable_name=level1_lable,num_name=data_name + num_name_end,
                                                  total_name=total_name, unit=unit,p_increase=False,
                                                  p_quantity=False, percentage=percentage)
            for level1_lable in level1_lable_list:
                if level1_lable[-2:] == '总体':pass
                else:
                    lable_data = data.loc[level1_lable]
                    lables_str_ord[level1_lable+'结构分析'] = one_layer_analyse(lable_data ,top,to_str=True,lable_level1=level1_lable )
            return lables_str_ord

        ############    开始进行分析    ############
        if isinstance(data.index, pd.MultiIndex) == False:
            lables_str_ord = one_layer_analyse(data,top)
        else:
            lables_str_ord = lable_analyse_MultiIndex(data,top)
        if save ==True:
            if save_name == None:
                column = "-".join(list(data.index.names))
                p1_name = p1_name.replace('年', '')
                p1_name = p1_name.replace('月', '')
                p2_name = p2_name.replace('年', '')
                p2_name = p2_name.replace('月', '')
                save_name = self.floder_form + '分析' + '_' + column + '（' + p1_name + '-' + p2_name + '）'
            self.txt_ord_tostr_save(lables_str_ord, self.floder_form + save_name)
        return lables_str_ord

    ##################    分析文字设计    #####################

    # 输出区域指标文字描述，并保存区域指标表及txt
    def area_target_txt(self,form_name='1_区域指标表.xlsx',txt_name= '1_区域指标分析.txt'):
        # 输出区域指标文字描述{分析标题；分析内容str}
        def complain_target_txt(area_target_ordict,satisfied = False):

            ############     投诉量分析  #############
            data_quantity,total_index = self.get_frame_and_totalindex(area_target_ordict,sheet_name = '投诉量')# 从dict中提取数据，及包含'总体'二字的index

            #>>>>>>>>>>总体数据分析>>>>>>>>>
            # 对投诉量的同比环比增长情况进行分析
            total_quntity = self.one_lable_str(data_quantity,total_index,lable_name='昆明市',num_name='投诉量',unit1 ='件',unit2 ='件',
                                           proporat=False,total_name='总体',mode='all')
            # 通过往期数据预测后两期走势
            total_quntity_forecast = self.forecast_lastyear(data_quantity,total_index,num_name='投诉量')
            complaint_total_quantity = total_quntity + total_quntity_forecast

            #>>>>>>>>>>区域排名分析>>>>>>>>>>>>
            # 获得投诉量排名的分析结果
            quntity_rank = self.get_top_and_last_str(data_quantity,total_index, '投诉量',self.this_period_column_name, num_name='投诉量',
                                                         lable_name='区县',mode='all', percentage=False,proportion=True,top=4,unit='件')
            quntity_rank_increase = self.get_top_and_last_str(data_quantity,total_index, '投诉量','同比增长量', num_name='投诉同比增长量',
                                                         lable_name='区县',mode='top', percentage=False,proportion=True,top=4,unit='件')
            quntity_rank_increase2 = self.get_top_and_last_str(data_quantity, total_index, '投诉量', '环比增长量',num_name='投诉环比增长量',
                                                              lable_name='区县', mode='top', percentage=False,proportion=True, top=4, unit='件')
            quntity_rank = quntity_rank + quntity_rank_increase + quntity_rank_increase2
            #获得同比与环比增长排名前三后三，及同比前三后三的文字
            tolast_yeat_rank = self.get_top_and_last_str(data_quantity, total_index,'投诉量', '同比增长率', num_name='投诉量同比增长率',
                                                         lable_name='区县', mode='all', percentage=True,top=3)
            tolast_period_rank = self.get_top_and_last_str(data_quantity,total_index, '投诉量', '环比增长率', num_name='投诉量环比增长率',
                                                           lable_name='区县', mode='all', percentage=True,top=3)
            complaint_area_quantity = quntity_rank + tolast_yeat_rank + tolast_period_rank


            #############  平均办结时长分析  ##############
            data_downtime, total_index2 = self.get_frame_and_totalindex(area_target_ordict, sheet_name='平均办结时长')
            # >>>>>>>>>>总体数据分析>>>>>>>>>
            total_downtime = self.one_lable_str(data_downtime, total_index2, lable_name='昆明市', num_name='平均办结时长', unit1='天',unit2='天',
                                               proporat=False, total_name='总体', mode='all')
            # >>>>>>>>>>区域排名分析>>>>>>>>>>>>
            downtime_rank = self.get_top_and_last_str(data_downtime,total_index, '平均办结时长', self.this_period_column_name, num_name='平均办结时长',
                                                     lable_name='区县', mode='all', percentage=False, top=3,unit='天')
            downtime_tolast_period_rank = self.get_top_and_last_str(data_downtime,total_index, '平均办结时长', '环比增长量',num_name='平均办结时长环比增长量',
                                                      lable_name='区县', mode='all', percentage=False, top=3,unit='天')
            downtime_tolast_year_rank = self.get_top_and_last_str(data_downtime, total_index,'平均办结时长', '同比增长量',num_name='平均办结时长同比增长量',
                                                                  lable_name='区县', mode='all', percentage=False,top=3,unit='天')
            complaint_downtime = total_downtime + downtime_rank + downtime_tolast_period_rank + downtime_tolast_year_rank

            #############  首周办结率分析  ##############
            data_7daydown, total_index3 = self.get_frame_and_totalindex(area_target_ordict, sheet_name='首周办结率')
            # >>>>>>>>>>总体数据分析>>>>>>>>>
            total_7daydown = self.one_lable_str(data_7daydown, total_index3, lable_name='昆明市', num_name='首周办结率',
                                                unit1='', unit2='个百分点',proporat=False, total_name='总体', mode='num',percent=True)

            # >>>>>>>>>>区域排名分析>>>>>>>>>>>>
            daydown_rank = self.get_top_and_last_str(data_7daydown, total_index,'首周办结率', self.this_period_column_name, num_name='首周办结率',
                                                     lable_name='区县', mode='all', percentage=True, top=3,unit='')
            daydown_tolast_period_rank = self.get_top_and_last_str(data_7daydown, total_index,'首周办结率', '环比增长量',num_name='首周办结率环比增长量',
                                                      lable_name='区县', mode='all', percentage=False, top=3,unit='个百分点')
            daydown_tolast_year_rank = self.get_top_and_last_str(data_7daydown, total_index,'首周办结率', '同比增长量',num_name='首周办结率同比增长量',
                                                                  lable_name='区县', mode='all', percentage=False,top=3,unit='个百分点')

            complaint_7daydown = total_7daydown + daydown_rank + daydown_tolast_period_rank + daydown_tolast_year_rank

            #############  满意度分析  ##############
            data_satisfied, total_index4 = self.get_frame_and_totalindex(area_target_ordict, sheet_name='满意度')
            # >>>>>>>>>>总体数据分析>>>>>>>>>
            total_satisfied = self.one_lable_str(data_satisfied, total_index4, lable_name='昆明市', num_name='满意度',
                                                unit1='', unit2='个百分点', proporat=False, total_name='总体', mode='num',percent=True)

            # >>>>>>>>>>区域排名分析>>>>>>>>>>>>
            satisfied_rank = self.get_top_and_last_str(data_satisfied, total_index,'满意度', self.this_period_column_name,num_name='满意度',
                                                     lable_name='区县', mode='all', percentage=False, top=3, unit='')
            satisfied_tolast_period_rank = self.get_top_and_last_str(data_satisfied, total_index,'满意度', '环比增长量',num_name='满意度环比增长量',
                                                                   lable_name='区县', mode='all', percentage=False, top=3,unit='个百分点')
            satisfied_tolast_year_rank = self.get_top_and_last_str(data_satisfied, total_index,'满意度', '同比增长量', num_name='满意度同比增长量',
                                                                 lable_name='区县', mode='all', percentage=False, top=3,unit='个百分点')
            complaint_satisfied = total_satisfied + satisfied_rank + satisfied_tolast_period_rank + satisfied_tolast_year_rank

            complaint_target_area = collections.OrderedDict()
            complaint_target_area['昆明市总体投诉量分析'+ '\n'] = complaint_total_quantity+ '\n'
            complaint_target_area['各区县市场环境建设情况分析'+ '\n'] = complaint_area_quantity+ '\n'
            complaint_target_area['各区县行政效能分析'+ '\n'] = complaint_downtime+ '\n'
            complaint_target_area['各区县投诉处理及时性分析'+ '\n'] = complaint_7daydown+ '\n'

            if satisfied == True :
                complaint_target_area['各区县投诉处理满意度分析'+ '\n'] = complaint_satisfied+ '\n'

            return complaint_target_area
        area_target_ordict = self.form_area_target(form_name) # 获取并保存指标表
        complain_target_txt_ord = complain_target_txt(area_target_ordict, satisfied=False) # 获取文字描述内容ord
        self.txt_ord_tostr_save(complain_target_txt_ord,self.floder_form + txt_name) # 整合文字的ord名并储存

        return complain_target_txt_ord
    #对一列数据生成指标表，并输出文字分析内容
    def one_feature(self,data_name,lable_column,
                    lable_name,num_column='登记编号',num_name = '量',total_lable_name='昆明市总体',unit='件', top='all',
                    count_way = 'count',func_part = None,func_all = None,save_name_form=None,save_name_txt=None,
                    num_column2=None,count_way2=None, new_target_func=None):
        '''
        :param data_name:str'投诉'、'举报'、'咨询'，通过self.get_data(data_name)获取数据
        :param lable_column:str lable列 列名
        :param lable_name: str 特征的统称 如： 区域
        :param num_column: str 用于统计计数列的 列名 ，默认：登记编号
        :param num_name: 计数指标的名称，默认：量，还有平均办结时长，挽回经济损失等
        :param total_lable_name: 定义指标表中总体标签的名称，默认：昆明市总体
        :param unit: str 默认：件 为进行分析时所用的单位，如分析中涉及百分点则不适用
        :param top: ‘0’，‘all’，‘int’：为‘0’代表不做排名分析，直接对所有lable单独分析，all对所有lable进行分析，同时也做排名分析
        :param count_way: 计数方法，默认：'count'，还可用'sum'、'mean'在target_groupby 中增加计数方法
        :param func_part: 用于截取部分数据的func 要求传入 data，return patr_data默认 None
        :param save_name_form: 会自动加上data_name做前缀，保存的指标报表名 默认 None
        :param save_name_txt: 会自动加上data_name做前缀，保存的分析文件名 默认 None
        :return:None，保存报表及分析文字
        '''
        ######   整理所需参数  #######
        data = self.get_data(data_name)
        target_name = data_name + num_name
        def func_default(data):
            part = data[data[lable_column].notnull()==True]
            return part
        if func_all != None:
            data = func_all(data)
        if func_part == None:
            func_part = func_default
        if save_name_form == None:
            save_name_form = self.floder_form + lable_name + target_name + '指标表.xlsx'
        else:save_name_form = self.floder_form + save_name_form
        if save_name_txt == None:
            save_name_txt = lable_name + target_name + '分析.txt'
        else:save_name_txt = save_name_txt
        part_data = func_part(data)

        ######   整理并储存相应指标表  #######
        #获取所需的指标表字典(里面只有一个指标表)
        target_ordict = self.target_arrange(data, func_part,lable_column, num_column,target_name,
                                            total_lable_name=total_lable_name,calculation=count_way,
                                            sort_asc=False, save=False, num_column_name2=num_column2,
                                            calculation2=count_way2, new_target_func=new_target_func)
        #加入总体的发展数据
        total_growth = self.groupby_2stage(data,['year',self.period], num_column,count_way=count_way,
                                           num_column2 = num_column2,count_way2 = count_way2,new_target_func=new_target_func)
        target_ordict[total_lable_name] = total_growth

        #加入各个lable的发展数据
        group_list = [lable_column,'year',self.period]
        lable_ord = self.groupby_3stage_ord(part_data, group_list, num_column,count_way=count_way,short='date',
                                            num_column2=num_column2, count_way2=count_way2,new_target_func=new_target_func)
        top_lable_list = self.get_top_lable_this_period(part_data,lable_column,top = top)

        for lable in top_lable_list:
            target_ordict[lable] = lable_ord[lable]

        self.save_excel_sheets(target_ordict, save_name_form)#保存该列指标的统计分析表格

        ######   输出并保存文字分析内容  #######
        # 从dict中提取数据，及包含'总体'二字的index
        target_frame, total_index = self.get_frame_and_totalindex(target_ordict, sheet_name= target_name )
        #frame中lable列的列名与sheet名称是一致的
        txt_part_ord = self.one_sheet_str(target_frame, total_index, save_name_txt, data_name,lable_column= target_name ,
                                          lable_name=lable_name,total_name= total_lable_name , top=top, unit=unit)
        return target_frame,txt_part_ord
